﻿using Hjt212Parser;
using log4net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using HpSocketIotGateway.Properties;

namespace HpSocketIotGateway.Facade
{
    public class SplitPackage
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(SplitPackage));
        private static readonly ConcurrentDictionary<SplitPackageKey, string> splitPackages = new ConcurrentDictionary<SplitPackageKey, string>();

        public static bool IsSplitPackage(int? i)
        {
            return i.HasValue && ((i.Value & 2) == 2);
        }
        ////必须1号先来，最后号后来，中间丢失可能不影响
        //public static void SplitPackageProcess(string msg)
        //{
        //    ClearTimeoutInfo();

        //    var pnum = Parser.GetIntByKey("PNUM", msg);
        //    if (!pnum.HasValue || pnum.Value < 2) return;

        //    var pno = Parser.GetIntByKey("PNO", msg);
        //    if (!pnum.HasValue) return;

        //    var mn = Parser.GetStringByKey("MN", msg);
        //    if (string.IsNullOrWhiteSpace(mn)) return;

        //    var cn = Parser.GetStringByKey("CN", msg);
        //    if (string.IsNullOrWhiteSpace(cn)) return;

        //    var datatime = Parser.GetDateTimeByKey("DataTime", msg);
        //    if (!datatime.HasValue) return;

        //    var key = new SplitPackageKey(mn, cn, datatime.Value, pnum.Value);

        //    if (pno.Value == 1)
        //    {
        //        if (splitPackages.ContainsKey(key)) return;
        //        string value = Parser.GetStringByKey("DataSegment", msg);
        //        if (string.IsNullOrWhiteSpace(value))
        //        {
        //            Log.Warn("No DataSegment:" + msg);
        //            return;
        //        }
        //        value = Regex.Replace(value, "PNUM=.;", "");
        //        value = Regex.Replace(value, "PNO=.;", "");
        //        value = Regex.Replace(value, ";Flag=.;", ";Flag=0;");
        //        var cp = Parser.GetStringByKey("CP", msg);
        //        key.CreateTime = DateTime.Now;
        //        key.ThePnos.Add(pno.Value);

        //        splitPackages.TryAdd(key, Regex.Replace(value, "CP=&&.*&&", "") + "CP=&&" + cp);
        //    }
        //    else
        //    {
        //        if (pno.Value <= pnum.Value)
        //        {
        //            if (!splitPackages.ContainsKey(key))
        //            {
        //                Log.Warn("No PNO<" + pno.Value + " package:" + msg);
        //                return;
        //            }
        //            string v = null;
        //            splitPackages.TryGetValue(key, out v);

        //            if (string.IsNullOrWhiteSpace(v) || v.Length < 4)
        //            {
        //                Log.Warn("No DataSegment:" + v);
        //                return;
        //            }
        //            key = GetKey(splitPackages, key);

        //            if (key.ThePnos.Contains(pno.Value)) return;

        //            key.ThePnos.Add(pno.Value);
        //            var cp = Parser.GetStringByKey("CP", msg);
        //            v = v + ";" + cp;
        //            if (pno.Value < pnum.Value)
        //            {
        //                splitPackages.TryRemove(key, out _);
        //                splitPackages.TryAdd(key, v);
        //            }
        //            else if (pno.Value == pnum.Value)
        //            {
        //                v = v + "&&";
        //                BufferFacade.EnqueueToMessageQueue(Crc.WrapByCrc(v, "monitor"));
        //            }
        //        }
        //        else
        //        {
        //            Log.Error("PNO>PNUM");
        //        }
        //    }

        //}
        /// <summary>
        /// 只要包数总和对就成交
        /// </summary>
        public static void SplitPackageProcess(string msg)
        {
            ClearTimeoutBufferSubPackage();
            var isLengthRight = Parser.IsLengthRight(msg);
            if (!isLengthRight)
            {
                return;
            }

            var pnum = Parser.GetIntByKey("PNUM", msg);
            if (!pnum.HasValue || pnum.Value < 2)
            {
                return;
            }

            var pno = Parser.GetIntByKey("PNO", msg);
            if (!pno.HasValue)
            {
                return;
            }

            var mn = Parser.GetStringByKey("MN", msg);
            if (string.IsNullOrWhiteSpace(mn))
            {
                return;
            }

            var cn = Parser.GetStringByKey("CN", msg);
            if (string.IsNullOrWhiteSpace(cn) || cn.Length < 2)
            {
                return;
            }

            var genCn = cn;
            if (Settings.Default.IsGenCmdDifferent)
            {
                genCn = "G" + cn.Substring(1);
            }
            var datatime = Parser.GetDateTimeByKey("DataTime", msg);
            if (!datatime.HasValue)
            {
                return;
            }

            var key = new SplitPackageKey(mn, cn, datatime.Value, pnum.Value);

            if (!splitPackages.ContainsKey(key))
            {
                string value = Parser.GetStringByKey("DataSegment", msg);
                if (string.IsNullOrWhiteSpace(value))
                {
                    Log.Warn("No DataSegment:" + msg);
                    return;
                }
                value = Regex.Replace(value, "PNUM=.;", "");
                value = Regex.Replace(value, "PNO=.;", "");
                value = Regex.Replace(value, ";Flag=.;", ";Flag=0;");
                value= Regex.Replace(value, ";CN="+cn+";", ";CN=" + genCn + ";");
                var cp = Parser.GetStringByKey("CP", msg);
                key.CreateTime = DateTime.Now;
                key.ThePnos.Add(pno.Value);
                splitPackages.TryAdd(key, Regex.Replace(value, "CP=&&.*&&", "") + "CP=&&" + cp);
            }
            else
            {
                string v = null;
                splitPackages.TryGetValue(key, out v);

                if (string.IsNullOrWhiteSpace(v) || v.Length < 4)
                {
                    Log.Warn("No DataSegment:" + v);
                    return;
                }
                key = GetKey(splitPackages, key);
                if (key.ThePnos.Contains(pno.Value))
                {
                    return;
                }

                key.ThePnos.Add(pno.Value);
                var cp = Parser.GetStringByKey("CP", msg);
                v = v + ";" + cp;

                splitPackages.TryRemove(key, out _);

                if (key.ThePnos.Count < pnum.Value)
                {
                    splitPackages.TryAdd(key, v);
                }
                else if (key.ThePnos.Count == pnum.Value)
                {
                    v = v + "&&";
                    BufferFacade.EnqueueToMessageQueue(Crc.WrapByCrc(v, "monitor"));
                }
                else
                {
                    Log.Warn("Why key.ThePnos.Count > pnum.Value.");
                }
            }

        }

        private static void ClearTimeoutBufferSubPackage()
        {

            if (MyTimer.IsToTheTime("SplitPackage.SplitPackageProcess", 10))
            {
                var now = DateTime.Now;
                List<SplitPackageKey> keyList = new List<SplitPackageKey>();
                var keys = splitPackages.Keys;
                foreach (var overDueKey in keys)
                {
                    if (overDueKey.CreateTime == null || Math.Abs((now - overDueKey.CreateTime).TotalMinutes) > 10)
                    {
                        keyList.Add(overDueKey);
                    }
                }
                string strList = null;
                foreach (var overDueKey in keyList)
                {
                    splitPackages.TryRemove(overDueKey, out strList);
                    Log.Warn("Matching failure:" + strList);

                }
            }
        }

        private static SplitPackageKey GetKey(ConcurrentDictionary<SplitPackageKey, string> splitPackages, SplitPackageKey key)
        {
            var keys = splitPackages.Keys;
            foreach (var k in keys)
            {
                if (k.Equals(key))
                {
                    return k;
                }
            }
            return null;
        }
    }
}
